package com.shuimin.group.mid.redis;

import com.shuimin.group.util.Tool;
import pond.common.S;
import pond.common.STRING;
import redis.clients.jedis.*;
import java.util.*;

public final class RedisUtil {
    //todo 注意事项，Redis 存取的值不能为null，可以是"", 如果有null 会出错，中断其他操作

    //Redis服务器IP
    private static String ADDR = "106.14.10.126";

    //Redis的端口号
    private static int PORT = 6379;

    //访问密码
    private static String AUTH = "admingroup";

    //可用连接实例的最大数目，默认值为8；
    //如果赋值为-1，则表示不限制；如果pool已经分配了maxActive个jedis实例，则此时pool的状态为exhausted(耗尽)。
    private static int MAX_ACTIVE = 1024;

    //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例，默认值也是8。
    private static int MAX_IDLE = 200;

    //等待可用连接的最大时间，单位毫秒，默认值为-1，表示永不超时。如果超过等待时间，则直接抛出JedisConnectionException；
    private static int MAX_WAIT = 10000;

    private static int TIMEOUT = 10000;

    //在borrow一个jedis实例时，是否提前进行validate操作；如果为true，则得到的jedis实例均是可用的；
    private static boolean TEST_ON_BORROW = true;

    private static JedisPool jedisPool = null;

    /**
     * 初始化Redis连接池
     */
    static {
        try {
            JedisPoolConfig config = new JedisPoolConfig();
            config.setMaxTotal(MAX_ACTIVE);
            config.setMaxIdle(MAX_IDLE);
            config.setMaxWaitMillis(MAX_WAIT);
            config.setTestOnBorrow(TEST_ON_BORROW);
            jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH);
            //jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取Jedis实例
     *
     * @return
     */
    public static long getNum =0;
    public static long returnNum =0;
    public synchronized static Jedis getJedis() {
        S.echo(Tool.getDate(S.now(),"yyyy-MM-dd HH:mm:ss")+" getJedis ="+ (getNum++));
        try {
            if (jedisPool != null) {
                Jedis resource = jedisPool.getResource();
                return resource;
            } else {
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 释放jedis资源
     *
     * @param jedis
     */
    public static void returnResource(final Jedis jedis) {
        S.echo(Tool.getDate(S.now(),"yyyy-MM-dd HH:mm:ss")+" returnResource ="+ (returnNum++));
        if (jedis != null) {
            jedis.close();
        }
    }

    public static List<String> keys(String pattern) {
        Jedis jedis = getJedis();
        if (null == jedis) {
            return new ArrayList<>();
        }
        Set<String> set = jedis.keys(pattern);
        returnResource(jedis);
        return new ArrayList<>(set);
    }

    public static boolean set(String key, String val) {
        if (STRING.isBlank(key) || STRING.isBlank(val))
            return false;
        Jedis jedis = getJedis();
        if (null == jedis)
            return false;
        String result = jedis.set(key,val);
        returnResource(jedis);
        if("OK".equals(result))
            return true;
        return false;
    }
    public static boolean rename(String old_key, String new_key) {
        if (STRING.isBlank(old_key) || STRING.isBlank(new_key) )
            return false;
        Jedis jedis = getJedis();
        if (null == jedis) {
            return false;
        }
        String result = jedis.rename(old_key,new_key);
        returnResource(jedis);
        if("OK".equals(result))
            return true;
        return false;
    }
    public static long incr (String key) {
        Jedis jedis = getJedis();
        if (null == jedis) {
            return 0;
        }
        long val = jedis.incr(key);
        returnResource(jedis);
        return val;
    }
    public static List<String> scanKey(String pattern) {
        List<String> list = new ArrayList<>();
        if (STRING.isBlank(pattern))
        {
            return list;
        }
        Jedis jedis = getJedis();
        if (null == jedis) {
            return list;
        }
        ScanParams scanParams = new ScanParams();
        scanParams.match(pattern);
        String cursor = redis.clients.jedis.ScanParams.SCAN_POINTER_START;
        boolean cycleIsFinished = false;
        while (!cycleIsFinished) {
            ScanResult<String> scanResult = jedis.scan(cursor, scanParams);
            list.addAll(scanResult.getResult());
            cursor = scanResult.getStringCursor();
            if (cursor.equals("0")) {
                cycleIsFinished = true;
            }
        }
        returnResource(jedis);
        return list;
    }

    public static boolean exist(String key) {
        Jedis jedis = getJedis();
        if (null == jedis)
        {
            return false;
        }
        boolean ret = jedis.exists(key);
        returnResource(jedis);
        return ret;
    }

    public static boolean delKey(String key) {
        if (STRING.isBlank(key))
            return false;
        Jedis jedis = getJedis();
        if (null == jedis ) {
            return false;
        }
        jedis.del(key);
        returnResource(jedis);
        return true;
    }

    public static boolean delKeys(List<String> keyList) {
        if (null == keyList || keyList.size() == 0)
            return false;
        Jedis jedis = getJedis();
        if (null == jedis) {
            return false;
        }
        jedis.del(keyList.toArray(new String[keyList.size()]));
        returnResource(jedis);
        return true;
    }

    /*
    * hash get vals
    * */
    public static String hGetFieldVal(String key, String field) {
        if (STRING.isBlank(key) || STRING.isBlank(field))
            return "";
        Jedis jedis = getJedis();
        if (null == jedis) {
            return "";
        }
        String val = jedis.hget(key,field);
        if (STRING.isBlank(val))
        {
            val = "";
        }
        returnResource(jedis);
        return val;
    }
    public static boolean hSetFieldVal(String key, String field, String val) {
        if (STRING.isBlank(key) || STRING.isBlank(field) || STRING.isBlank(val))
            return false;
        Jedis jedis = getJedis();
        if (null == jedis) {
            return false;
        }
        jedis.hset(key,field,val);
        returnResource(jedis);
        return true;
    }
    public static Map<String, Object> hscanObjectsFromKey(String key) {

        Map<String, Object> map = new HashMap<>();
        Jedis jedis = getJedis();
        if (null == jedis) {
            return map;
        }

        String cursor = redis.clients.jedis.ScanParams.SCAN_POINTER_START; // 返回0 说明遍历完成
        boolean cycleIsFinished = false;
        while (!cycleIsFinished) {
            ScanResult<Map.Entry<String, String>> hscanResult = jedis.hscan(key, cursor);
            List<Map.Entry<String, String>> scanResult = hscanResult.getResult();
            for (int m = 0; m < scanResult.size(); m++) {
                Map.Entry<String, String> mapentry = scanResult.get(m);
                map.put(mapentry.getKey(), mapentry.getValue());
            }
            cursor = hscanResult.getStringCursor();
            if (cursor.equals("0")) {
                cycleIsFinished = true;
            }
        }
        returnResource(jedis);
        return map;
    }
    public static Map<String, String> hscanFromKey(String key) {
        Map<String, String> map = new HashMap<>();
        Jedis jedis = getJedis();
        if (null == jedis)
        {
            return map;
        }
        String cursor = redis.clients.jedis.ScanParams.SCAN_POINTER_START; // 返回0 说明遍历完成
        boolean cycleIsFinished = false;
        while (!cycleIsFinished) {
            ScanResult<Map.Entry<String, String>> hscanResult = jedis.hscan(key, cursor);
            List<Map.Entry<String, String>> scanResult = hscanResult.getResult();
            for (int m = 0; m < scanResult.size(); m++) {
                Map.Entry<String, String> mapentry = scanResult.get(m);
                map.put(mapentry.getKey(), mapentry.getValue());
            }
            cursor = hscanResult.getStringCursor();
            if (cursor.equals("0")) {
                cycleIsFinished = true;
            }
        }
        returnResource(jedis);
        return map;
    }
    public static List<Map<String, Object>> hscanObjectFromKeys(List<String> keyList) {
        List<Map<String, Object>> retList = new ArrayList<>();
        if (null == keyList || keyList.size() == 0) {
            return retList;
        }
        Jedis jedis = getJedis();
        if (null == jedis) {
            return retList;
        }
        S._for(keyList).each(key -> {
            String cursor = redis.clients.jedis.ScanParams.SCAN_POINTER_START; // 返回0 说明遍历完成
            Map<String, Object> map = new HashMap<>();
            boolean cycleIsFinished = false;
            while (!cycleIsFinished) {
                ScanResult<Map.Entry<String, String>> hscanResult = jedis.hscan(key, cursor);
                List<Map.Entry<String, String>> scanResult = hscanResult.getResult();
                for (int m = 0; m < scanResult.size(); m++) {
                    Map.Entry<String, String> mapentry = scanResult.get(m);
                    map.put(mapentry.getKey(), mapentry.getValue());
                }
                cursor = hscanResult.getStringCursor();
                if (cursor.equals("0")) {
                    cycleIsFinished = true;
                }
            }
            retList.add(map);
        });
        returnResource(jedis);
        return retList;
    }
    public static List<Map<String, String>> hscanFromKeys(List<String> keyList) {
        List<Map<String, String>> retList = new ArrayList<>();
        if (null == keyList || keyList.size() == 0) {
            return retList;
        }
        Jedis jedis = getJedis();
        if (null == jedis) {
            return retList;
        }
        S._for(keyList).each(key -> {
            String cursor = redis.clients.jedis.ScanParams.SCAN_POINTER_START; // 返回0 说明遍历完成
            Map<String, String> map = new HashMap<>();
            boolean cycleIsFinished = false;
            while (!cycleIsFinished) {
                ScanResult<Map.Entry<String, String>> hscanResult = jedis.hscan(key, cursor);
                List<Map.Entry<String, String>> scanResult = hscanResult.getResult();
                for (int m = 0; m < scanResult.size(); m++) {
                    Map.Entry<String, String> mapentry = scanResult.get(m);
                    map.put(mapentry.getKey(), mapentry.getValue());
                }
                cursor = hscanResult.getStringCursor();
                if (cursor.equals("0")) {
                    cycleIsFinished = true;
                }
            }
            retList.add(map);
        });
        returnResource(jedis);
        return retList;
    }
    public static Map<String, Map<String, Object>> hscanMapFromKeys(List<String> keyList) {
        Map<String, Map<String, Object>> retMap = new HashMap<>();
        if (null == keyList || keyList.size() == 0) {
            return retMap;
        }
        Jedis jedis = getJedis();
        if (null == jedis)
        {
            return retMap;
        }
        S._for(keyList).each(key -> {
            String cursor = redis.clients.jedis.ScanParams.SCAN_POINTER_START; // 返回0 说明遍历完成
            Map<String, Object> map = new HashMap<>();
            boolean cycleIsFinished = false;
            while (!cycleIsFinished) {
                ScanResult<Map.Entry<String, String>> hscanResult = jedis.hscan(key, cursor);
                List<Map.Entry<String, String>> scanResult = hscanResult.getResult();
                for (int m = 0; m < scanResult.size(); m++) {
                    Map.Entry<String, String> mapentry = scanResult.get(m);
                    map.put(mapentry.getKey(), mapentry.getValue());
                }
                cursor = hscanResult.getStringCursor();
                if (cursor.equals("0")) {
                    cycleIsFinished = true;
                }
            }
            retMap.put(key, map);
        });
        returnResource(jedis);
        return retMap;
    }

    public static List<Map<String, Object>> hscanListFromKeys(List<String> keyList) {
        List<Map<String, Object>> retList = new ArrayList<>();
        if (null == keyList || keyList.size() == 0) {
            return retList;
        }
        Jedis jedis = getJedis();
        if (null == jedis) {
            return retList;
        }
        S._for(keyList).each(key -> {
            String cursor = redis.clients.jedis.ScanParams.SCAN_POINTER_START; // 返回0 说明遍历完成
            Map<String, Object> map = new HashMap<>();
            boolean cycleIsFinished = false;
            while (!cycleIsFinished) {
                ScanResult<Map.Entry<String, String>> hscanResult = jedis.hscan(key, cursor);
                List<Map.Entry<String, String>> scanResult = hscanResult.getResult();
                for (int m = 0; m < scanResult.size(); m++) {
                    Map.Entry<String, String> mapentry = scanResult.get(m);
                    map.put(mapentry.getKey(), mapentry.getValue());
                }
                cursor = hscanResult.getStringCursor();
                if (cursor.equals("0")) {
                    cycleIsFinished = true;
                }
            }
            retList.add(map);
        });
        returnResource(jedis);
        return retList;
    }
    public static boolean hAdd(Map<String, Map<String, String>> map) {
        if (null == map || map.size() == 0)
            return false;
        Jedis jedis = getJedis();
        if (null == jedis) {
            return false;
        }
        S._for(map).each(item -> {
            jedis.hmset(item.getKey(), item.getValue());
        });
        returnResource(jedis);
        return true;
    }
    public static boolean hAddOne(String key, Map<String, String> data) {
        if (STRING.isBlank(key) || null == data || data.size() == 0)
            return  false;
        Jedis jedis = getJedis();
        if (null == jedis) {
            return false;
        }
        jedis.hmset(key, data);
        returnResource(jedis);
        return true;
    }

    public static boolean delAndAdd(List<String> keyList, Map<String, Map<String, String>> map) {
        if (null == keyList || null == map)
            return  false;
        Jedis jedis = getJedis();
        if (null == jedis) {
            return false;
        }
        Transaction transaction = jedis.multi();
        if (keyList.size() > 0)
            transaction.del(keyList.toArray(new String[keyList.size()]));
        S._for(map).each(item -> {
            transaction.hmset(item.getKey(), item.getValue());
        });
        transaction.exec();
        returnResource(jedis);
        return true;
    }

    /*
    *  list
    * */
    public static long getListLenFromKey(String key)
    {
        long len = 0;
        if (STRING.isBlank(key))
           return  len;
        Jedis jedis = getJedis();
        if (null == jedis) {
            return len;
        }
        len = jedis.llen(key);
        returnResource(jedis);
        return len;
    }

    public static boolean enqueue(String key, String val) {
        if (STRING.isBlank(key) ||  STRING.isBlank(val))
            return false;
        Jedis jedis = getJedis();
        if (null == jedis) {
            return false;
        }
        jedis.lpush(key, val);
        returnResource(jedis);
        return true;
    }
    public static String dequeue(String key) {
        if (STRING.isBlank(key))
            return "";
        Jedis jedis = getJedis();
        // key 不存在则 没有数据需要出队
        if (null == jedis)
            return "";
        if (!jedis.exists(key))
        {
            returnResource(jedis);
            return "";
        }
        String result = jedis.rpop(key);
        returnResource(jedis);
        return result;
    }

    public static boolean pushStack(String key, String val) {
        if (STRING.isBlank(key) ||  STRING.isBlank(val))
            return false;
        Jedis jedis = getJedis();
        if (null == jedis ) {
            return false;
        }
        jedis.lpush(key, val);
        returnResource(jedis);
        return true;
    }

    /* map 只能存放不同的key ，加入各种stack */
    public static boolean pushDiffStack(Map<String,String> map) {
        if (null == map||  0 == map.size())
            return false;
        Jedis jedis = getJedis();
        if (null == jedis ) {
            return false;
        }
        S._for(map).each(item->{
            jedis.lpush(item.getKey(), item.getValue());
        });
        returnResource(jedis);
        return true;
    }
    public static List<String> queryAllKeysFromStack(String key)
    {
        List<String> list = new ArrayList<>();
        if (STRING.isBlank(key) )
            return list;
        Jedis jedis = getJedis();
        if (null == jedis) {
            return list;
        }
        if (!jedis.exists(key) )
        {
            returnResource(jedis);
            return list;
        }
        list.addAll(jedis.lrange(key,0, jedis.llen(key) -1));
        returnResource(jedis);
        return list;
    }

    // val = "" 或者 null 从第一个查询
    public static List<String> queryKeysFromStack(String key,  int num , String val) {
        List<String> list = new ArrayList<>();
        if (num <=0 || STRING.isBlank(key) )
            return list;
        Jedis jedis = getJedis();
        if (null == jedis) {
            return list;
        }
        if (!jedis.exists(key) )
        {
            returnResource(jedis);
            return list;
        }
        /* 本身也算，需要-1*/
        num = num -1;
        long len = jedis.llen(key);

        if (STRING.isBlank(val))
        {
            long end = num < len-1 ? num : len-1;
            list.addAll(jedis.lrange(key,0, end));
        }
        else
        {
            long start = len;
            for (long i =0; i <len; i++)
            {
                if (val.equals(jedis.lindex(key,i)))
                {
                    start = i;
                    break;
                }
            }
            if (start < len )
            {
                long end = (start+num) < len-1 ? (start+num) : len-1;
                end = (end >= start) ? end : len-1;
                list.addAll(jedis.lrange(key, start, end));
            }
        }
        returnResource(jedis);
        return list;
    }

    /*
    *  集合
    * */
    public static boolean sAddList(String key, List<String> list) {
        if (STRING.isBlank(key) ||null == list || list.size() == 0)
            return false;
        Jedis jedis = getJedis();
        if (null == jedis ) {
            return false;
        }
        jedis.sadd(key, list.toArray(new String[list.size()]));
        returnResource(jedis);
        return true;
    }
    public static boolean sAdd(String key, String member) {
        if (STRING.isBlank(key) || STRING.isBlank(member))
        {
            return false;
        }
        Jedis jedis = getJedis();
        if (null == jedis ) {
            return false;
        }
        jedis.sadd(key,member);
        returnResource(jedis);
        return true;
    }

    public static boolean sisMember(String key, String member) {
        if (STRING.isBlank(key) || STRING.isBlank(member))
        {
            return false;
        }
        boolean exist = false;
        Jedis jedis = getJedis();
        if (null == jedis ) {
            return exist;
        }
        exist = jedis.sismember(key,member);
        returnResource(jedis);
        return exist;
    }

    public static List<String> sMembers(String key) {
        List<String> members  = new ArrayList<>();
        if ( STRING.isBlank(key))
            return members;
        Jedis jedis = getJedis();
        if (null == jedis) {
            return members;
        }
        members = new ArrayList<>(jedis.smembers(key));
        returnResource(jedis);
        return members;
    }
    public static long scard(String key) {
        long size =0;
        if (STRING.isBlank(key))
            return size;
        Jedis jedis = getJedis();
        if (null == jedis) {
            return size;
        }
        size = jedis.scard(key);
        returnResource(jedis);
        return size;
    }
}